package com.wsl.sale.utils;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 雪花算法生成主键
 */
public class SnowFlakeIdGenerator {
    //the initial time(2017-01-01)
    private static final long INITIAL_TIME_STAMP=1556541985555L;
    // Machine ID bits
    private static final long WORK_ID_BITS = 5L;

    //DataCenter ID bits
    private static final long DATACENTER_ID_BITS = 5L;
    // The maximum machine ID supported is 31, which can quickly calculate the maximum decimal number that a few binary numbers can represent.
    private static final long MAX_WORK_ID= ~(-1L<<WORK_ID_BITS);
    //The maximum datacenter ID supported is 31
    private static final long MAX_DATACENTER_ID = ~(-1L<<DATACENTER_ID_BITS);
    //Sequence ID bits
    private static final long SEQUENCE_BITS =12L;
    //The datacent ID offset,12
    private static final long WORKERID_OFFSET = SEQUENCE_BITS;
    //The datacent ID offset,12+5
    private static final long DATACENTERID_OFFSET=WORK_ID_BITS+SEQUENCE_BITS;
    //The timestage offset，5+5+12
    private static final long TIMESTAMP_OFFSET=DATACENTER_ID_BITS+WORK_ID_BITS+SEQUENCE_BITS;
    //Sequence mask,4095
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
    //Worker ID 0-31
    private long workerId;
    //Datacenter ID,0-31
    private long datacenterId;
    //Sequence 0-4095
    private long sequence = 0L;
    //Last timestamp
    private long lastTimeStamp = -1L;

    public SnowFlakeIdGenerator(long workerId, long datacenterId) {
        if(workerId>MAX_WORK_ID || workerId<0){
            throw new IllegalArgumentException(String.format("WorkerID can't be greater than %d or less than 0",MAX_WORK_ID));
        }
        if(datacenterId>MAX_DATACENTER_ID || datacenterId<0){
            throw new IllegalArgumentException(String.format("DataCenterID  can't be greater than %d or less than 0",MAX_DATACENTER_ID));
        }
        this.workerId=workerId;
        this.datacenterId=datacenterId;
    }
    public synchronized long nextId(){
        long timeStamp =System.currentTimeMillis();
        if (timeStamp<lastTimeStamp){
            throw new RuntimeException("The current time less than last time");
        }
       if (timeStamp==lastTimeStamp){
            sequence = (sequence+1)&SEQUENCE_MASK;
            if (0==sequence){
                timeStamp = tillNextMillis(lastTimeStamp);
            }
       }else{
           sequence =0L;
       }
       lastTimeStamp = timeStamp;
       return (timeStamp-INITIAL_TIME_STAMP)<<TIMESTAMP_OFFSET | (datacenterId << DATACENTERID_OFFSET)|(workerId<<WORKERID_OFFSET)|sequence;
    }


    private long tillNextMillis(long lastTimeStamp){
        //获取单位为毫秒
        long timeStamp =System.currentTimeMillis();
        while (timeStamp <=lastTimeStamp){
            timeStamp = System.currentTimeMillis();
        }
        return timeStamp;
    }

    public static void main(String[] args) {
      /*  final SnowFlakeIdGenerator snowFlakeIdGenerator = new SnowFlakeIdGenerator(1, 1);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            executorService.execute(new Runnable() {
                public void run() {
                    long id = snowFlakeIdGenerator.nextId();
                    System.out.println(id);
                }
            });
        }
        executorService.shutdown();*/
        System.out.println(-1^(-1<<5));
    }
}
